﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using KandaAlpha.Domain.Model.Entities;
using KandaAlpha.Domain.Repository;
using System.Data;
using System.Linq.Expressions;
using System.Threading;
using System.Web;
using Db4objects.Db4o;
using System.Configuration;

namespace KandaAlpha.Infrastructure.Repository.db4o
{

    /// <summary>
    /// Manages the lifecycle of the db4o object container
    /// </summary>
    /// <remarks>Users client/servier model and stores client within web or thread context</remarks>
    public class ObjectContainerManager : IObjectContainerManager
    {

        internal const string KEY_DB4O_CLIENT = "db4oClient";

        [ThreadStatic]
        private static Hashtable _objectContainerThreadStorage;
        private static IObjectServer _objectServer = null;
    
        private readonly string _db4oPath; 
        private readonly int _db4oServerPort; 

        public ObjectContainerManager(string db4oPath, int db4oServerPort) 
        {
            _db4oPath = db4oPath;
            _db4oServerPort = db4oServerPort;
        }

        public IObjectServer ObjectServer
        {
            get
            {
                if (_objectServer == null)
                {
                    _objectServer = Db4oFactory.OpenServer(_db4oPath, _db4oServerPort);
                    Db4oFactory.Configure().GenerateUUIDs(int.MaxValue);
                }
                return _objectServer;
            }
        }

        /// <summary>
        /// ensures server is closed gracefully 
        /// </summary>
        public void CloseServer()
        {
            ObjectServer.Close();
            _objectServer = null;
            _objectContainerThreadStorage = null;
        }

        public IObjectContainer ObjectContainer
        {
            get
            {
                IObjectContainer objectContainer = null;
                   
                HttpContext context = HttpContext.Current;

                if (context != null) // web context
                {
                    objectContainer = context.Items[KEY_DB4O_CLIENT] as IObjectContainer;

                    if (objectContainer == null)
                    {
                        objectContainer = ObjectServer.OpenClient();
                        context.Items[KEY_DB4O_CLIENT] = objectContainer;
                    }      
                }
                else // thread context
                {
                    lock (this)
                    {
                        var storage = GetContainerThreadStorageHashtable();
                        if (storage.ContainsKey(KEY_DB4O_CLIENT))
                        {
                            objectContainer = GetContainerThreadStorageHashtable()[KEY_DB4O_CLIENT] as IObjectContainer;
                        }
                        if (objectContainer == null)
                        {
                            objectContainer = ObjectServer.OpenClient();
                            GetContainerThreadStorageHashtable()[KEY_DB4O_CLIENT] = objectContainer;
                        }
                    }              
                }
                return objectContainer;
            }

        }

        private Hashtable GetContainerThreadStorageHashtable()
        {
            return _objectContainerThreadStorage ?? (_objectContainerThreadStorage = new Hashtable());
        }


    }
}
